package com.yanghui.lingyue.functions.ktBase.qmLogic

import java.lang.Exception
import java.util.*

abstract class AbstractSmallestItem(val varNum: Int) {

    companion object {

        fun initNumToLogicArray(varNum: Int, initNum: Long): LinkedList<LogicItem> {
            var initNum = initNum
            if (varNum > 64) {
                throw ParseLogicException()
            }
            val result = LinkedList<LogicItem>()
            repeat(varNum) {
                when (initNum and 1L) {
                    0L -> result.add(LogicItem.Low)
                    1L -> result.add(LogicItem.High)
                }
                initNum = initNum ushr 1
            }
            return result
        }

        fun logicListToInitNum(varNum: Int, logicArray: LinkedList<LogicItem>): Long {
            if (varNum > 64 || logicArray.size != varNum) {
                throw ParseLogicException()
            }
            var result: Long = 0
            for (i in 0 until logicArray.size) {
                when (logicArray[i]) {
                    LogicItem.High -> result = result or (1L shl i)
                    LogicItem.Low -> {
                    }
                    LogicItem.X -> throw ParseLogicException()
                }
            }
            return result
        }
    }

    val varValueList: LinkedList<LogicItem> = LinkedList()

    fun equal(other: AbstractSmallestItem): Boolean {
        for (i in 0 until varNum) {
            if (this.varValueList[i] == other.varValueList[i])
                continue
            else
                return false
        }
        return true
    }
}

class OriginSmallestItem(varNum: Int, initNum: Long = 0L) : AbstractSmallestItem(varNum) {
    init {
        varValueList.addAll(initNumToLogicArray(varNum, initNum))
    }
}

class ChangedSmallestItem(varNum: Int) : AbstractSmallestItem(varNum) {

    val enableVarNumList = LinkedList<Long>()

    constructor(originItem: OriginSmallestItem) : this(originItem.varNum) {
        originItem.varValueList.forEach {
            this.varValueList.add(it)
        }
        enableVarNumList.add(logicListToInitNum(varNum, originItem.varValueList))
    }

    constructor(varValueList: LinkedList<LogicItem>) : this(varValueList.size) {
        this.varValueList.addAll(varValueList)
    }

    fun checkMerge(smallestItem: ChangedSmallestItem): ChangedSmallestItem? {
        if (this.varNum != smallestItem.varNum)
            return null
        val newSmallestItemList = LinkedList<LogicItem>()
        var cnt = 0
        for (i in 0 until varNum) {
            if (this.varValueList[i] == smallestItem.varValueList[i])
                newSmallestItemList.add(this.varValueList[i])
            else {
                cnt++
                if (cnt == 1) {
                    newSmallestItemList.add(LogicItem.X)
                } else {
                    return null
                }
            }
        }
        if (cnt == 0)
            return null
        val result = ChangedSmallestItem(newSmallestItemList)

        result.enableVarNumList.addAll(this.enableVarNumList)
        result.enableVarNumList.addAll(smallestItem.enableVarNumList)
        return result
    }

    fun getHighNum(): Int {
        var num = 0
        varValueList.forEach {
            if (it == LogicItem.High)
                num++
        }
        return num
    }

    fun toString(varList: LinkedList<Char>): String {
        var str = ""
        val varValueMap = TreeMap<Char, Boolean>()
        varValueList.forEachIndexed { index, logicItem ->
            when(logicItem) {
                LogicItem.Low -> varValueMap[varList[index]] = false
                LogicItem.High -> varValueMap[varList[index]] = true
                else ->{}
            }
        }
        varValueMap.forEach { (k, v) ->
            str += k
            if (!v)
                str += "'"
        }
        return str
    }
}

enum class LogicItem {
    High, Low, X
}

class ParseLogicException : Exception()
